import * as THREE from 'three';

import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { getAddress, getFakeData, getLines, getRandomInt, worldToScreen } from '@/core/tooler';
import { Line2 } from 'three/examples/jsm/lines/Line2.js'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js'


// import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline';

// import { MeshLine, MeshLineMaterial } from "./line.js"

//立方球和虚线动画

let group;
let topGroup;
let container, stats;
let camera, scene, renderer;
let topScene;
let selectedObject = null;
let overlay;

let pointMap;
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

let matLine;
// let linewidth = 4;

const config = {
    pointerColor: 0x00ff00,
    hoverColor: 0xff9900,
    lineColor: 0x00ff00,
    linewidth: 1,
    pointerSize: 20
}


export function init(canvas: any, $overlay: any) {
    overlay = $overlay;
    container = document.body;

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000);
    camera.position.z = 2000;

    const controls = new OrbitControls(camera, container);
    controls.minDistance = 100;
    controls.maxDistance = 30000;

    scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2(0x000000, 0.0004);

    topScene = new THREE.Scene();
    topScene.fog = new THREE.FogExp2(0x000000, 0.0004);

    group = new THREE.Group();
    scene.add(group);

    topGroup = new THREE.Group();
    topScene.add(topGroup);

    renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.autoClear = false;

    stats = new Stats();
    container.appendChild(stats.dom);

    window.addEventListener('resize', onWindowResize);
    document.addEventListener('pointermove', onPointerMove);

    let light = new THREE.DirectionalLight(0xffffff, 0.8);
    light.position.set(200, 200, 100);
    scene.add(light)

    matLine = new LineMaterial({
        color: config.lineColor,
        linewidth: config.linewidth, // in world units with size attenuation, pixels otherwise
        vertexColors: false,
        //resolution:  // to be set by renderer, eventually
        dashed: true,
        alphaToCoverage: false,
        worldUnits: true,
        opacity: 1,
        dashSize: 3,
        gapSize: 5,
    });


    addView(getFakeData(60));
    // topScene.add(new THREE.AxesHelper(100))
    animate();
}

function addView(data) {
    const points = getAddress(data);
    const lines = getLines(data);
    pointMap = addPoints(points);
    addCoinLines(lines, pointMap);
}

function addPoints(points: any[]) {
    // const sprite = new THREE.TextureLoader().load('./asset/img/pot.png');
    const map = {};
    for (let i = 0; i < points.length; i++) {
        // const pot = new THREE.Sprite(new THREE.SpriteMaterial({ color: config.pointerColor, map: sprite, sizeAttenuation: false, transparent: true, fog: true }));
        let geo = new THREE.SphereGeometry(config.pointerSize, 8, 8);
        let mat = new THREE.MeshBasicMaterial({color: new THREE.Color(config.pointerColor)});
        let mesh = new THREE.Mesh(geo, mat);
        let size = 800;
        let item = mesh;
        let x = getRandomInt(-size, size);
        let y = getRandomInt(-size, size);
        let z = getRandomInt(-size, size);
        // let r = getRandomInt(1, 6) * 0.01;
        item.position.set(x, y, z);
        // item.scale.set(r, r, r);
        topGroup.add(item);
        map[points[i]] = item;
    }
    return map;
}

function addLines(p1: THREE.Vector3, p2: THREE.Vector3, two = false) {
    if (two) {
        let ofs = config.linewidth / 2;
        p1.add(new THREE.Vector3(ofs, -ofs, 0))
        p2.add(new THREE.Vector3(ofs, -ofs, 0))
        addLine(p1, p2);
        let p3 = p1.clone().add(new THREE.Vector3(config.linewidth, -config.linewidth, 0));
        let p4 = p2.clone().add(new THREE.Vector3(config.linewidth, -config.linewidth, 0));
        addLine(p4, p3);
    }
    else {
        addLine(p1, p2);
    }

    // addPot(p1)
    // addPot(p2)
}

function addLine(p1: THREE.Vector3, p2: THREE.Vector3) {
    const positions = [];
    positions.push(p1.x, p1.y, p1.z)
    positions.push(p2.x, p2.y, p2.z)
    const geometry = new LineGeometry();
    geometry.setPositions(positions);
    let line = new Line2(geometry, matLine);
    line.computeLineDistances();
    line.scale.set(1, 1, 1);
    topGroup.add(line);
}


function addCoinLines(lines: any[], map: any) {
    const material = new THREE.LineDashedMaterial({ color: 0xffffff, transparent: true, opacity: 0.4, dashSize: 4, gapSize: 2 });
    lines.forEach(item => {
        const toObj = map[item.to];
        const fromObj = map[item.from];
        addLines(toObj.position.clone(), fromObj.position.clone(), true)


        // const points = [];
        // points.push(toObj.position);
        // points.push(fromObj.position);
        // const geometry = new THREE.BufferGeometry();
        // geometry.setFromPoints(points);
        // const line = new THREE.LineSegments(geometry, material);
        // line.computeLineDistances();
        // group.add(line);
    })
}

// 更新 DOM 元素的位置
function updateOverlayPosition() {
    if (!selectedObject) {
        overlay.style.transform = `translate(-200%, -200%)`;
        return;
    }
    const vector = worldToScreen(selectedObject, camera);
    const widthHalf = window.innerWidth / 2;
    const heightHalf = window.innerHeight / 2;
    const x = (vector.x * widthHalf) + widthHalf;
    const y = -(vector.y * heightHalf) + heightHalf;
    overlay.style.transform = `translate(-50%, -50%) translate(${x}px, ${y}px)`;
}


function onPointerMove(event) {
    if (selectedObject) {
        selectedObject.material.color.set(config.pointerColor);
        selectedObject = null;
    }

    pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
    pointer.y = - (event.clientY / window.innerHeight) * 2 + 1;

    raycaster.setFromCamera(pointer, camera);

    const intersects = raycaster.intersectObject(topGroup, true);

    if (intersects.length > 0) {

        const res = intersects.filter(function (res) {

            return res && res.object;

        })[0];

        if (res && res.object) {
            let find = false;
            for (let i in pointMap) {
                if (pointMap[i] == res.object) {
                    overlay.innerText = i;
                    find = true;
                    break;
                }
            }
            if(find){
                selectedObject = res.object;
                selectedObject.material.color.set(config.hoverColor);
            }
            

        }

    }

}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    requestAnimationFrame(animate);
    stats.update();
    updateOverlayPosition();
    render();
}

function render() {
    const time = Date.now() * 0.001;

    // group.rotation.y = time * 0.03;
    // topGroup.rotation.y = time * 0.03;
    matLine.resolution.set(window.innerWidth, window.innerHeight);
    matLine.dashOffset += 0.1;
    renderer.clear();
    renderer.render(scene, camera);
    renderer.clearDepth();
    renderer.render(topScene, camera);
}